#include "UartTask.h"

#include <stdio.h>						//uart redirect fputc
#include <string.h>						//copy function
#include <stdarg.h>						//va_start /vsnprintf /va_end function
#include "main.h"
#include "cmsis_os.h"
#include "usart.h"
#include "task.h"

#include "MPU6050.h"
#include "MotorCtrlTask.h"
#define UART_DEBUG &huart3

#define	BUFFER_SIZE	256					//串口DMA发送接收数组大小

extern osSemaphoreId_t Uart3RxSemaphoreHandle;

typedef	struct
{
		uint8_t rxBuf[BUFFER_SIZE];  	 	//接收数据数组
		uint8_t txBuf[BUFFER_SIZE];  	 	//发送数据数组
		uint8_t buff[BUFFER_SIZE];  	//接收数据缓存数组
		uint8_t recive_count;							 	//接收计数
}UART_DMADAT;
 
UART_DMADAT	uartDMA_data;


/*LED Task*/
static TaskHandle_t LED_Task_Handle = NULL;
static void LED_Task(void* pvParameters);

/*UartTx Task*/
static TaskHandle_t UartTx_Task_Handle = NULL;
static void UartTx_Task(void* pvParameters);

/*UartTx Task*/
static TaskHandle_t UartRx_Task_Handle = NULL;
static void UartRx_Task(void* pvParameters);


/*IMU Task*/
static TaskHandle_t IMU_Task_Handle = NULL;
void IMU_Task(void* pvParameters);

/*MotorCtrl Task*/
static TaskHandle_t MotorCtrl_Task_Handle = NULL;
void MotorCtrl_Task(void* pvParameters); 






//获取CubeMx创建的启动任务句柄  该任务优先级必须最高
extern osThreadId_t FreeRTOSTaskCreHandle;
//由cubemx创建的启动任务 后续全部改为Freertos标准函数以方便移植
void StartFreeRTOSTaskCreate(void *argument)
{
	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值，默认为 pdPASS */
	taskENTER_CRITICAL(); //进入临界区
	/* 创建 LED_Task 任务 */
	xReturn = xTaskCreate((TaskFunction_t )LED_Task, /* 任务入口函数 */
	(const char* )"LED_Task",/* 任务名字 */
	(uint16_t )128, /* 任务栈大小 */
	(void* )NULL, /* 任务入口函数参数 */
	(UBaseType_t )1, /* 任务的优先级 */
	(TaskHandle_t* )&LED_Task_Handle);/* 任务控制块指针 */
	if (pdPASS == xReturn)
		printf("创建 LED_Task 任务成功!\r\n");
	
		/* 创建 UartTx_Task 任务 */
	 xReturn = xTaskCreate((TaskFunction_t )UartTx_Task, /* 任务入口函数 */
	(const char* )"UartTx_Task",/* 任务名字 */
	(uint16_t )512, /* 任务栈大小 */
	(void* )NULL, /* 任务入口函数参数 */
	(UBaseType_t )2, /* 任务的优先级 */
	(TaskHandle_t* )&UartTx_Task_Handle);/* 任务控制块指针 */
	if (pdPASS == xReturn)
		printf("创建 UartTx_Task 任务成功!\r\n");
	
	
		/* 创建 UartRx_Task 任务 */
	xReturn = xTaskCreate((TaskFunction_t )UartRx_Task, /* 任务入口函数 */
	(const char* )"UartRx_Task",/* 任务名字 */
	(uint16_t )512, /* 任务栈大小 */
	(void* )NULL, /* 任务入口函数参数 */
	(UBaseType_t )3, /* 任务的优先级 */
	(TaskHandle_t* )&UartRx_Task_Handle);/* 任务控制块指针 */
	if (pdPASS == xReturn)
		printf("创建 UartRx_Task 任务成功!\r\n");


	
	/* 创建 IMU_Task 任务 */
	xReturn = xTaskCreate((TaskFunction_t )IMU_Task, /* 任务入口函数 */
	(const char* )"IMU_Task",/* 任务名字 */
	(uint16_t )512, /* 任务栈大小 */
	(void* )NULL, /* 任务入口函数参数 */
	(UBaseType_t )4, /* 任务的优先级 */
	(TaskHandle_t* )&IMU_Task_Handle);/* 任务控制块指针 */
	if (pdPASS == xReturn)
		printf("创建 IMU_Task 任务成功!\r\n");
	
		/* 创建 MotorCtrl_Task 任务 */
	xReturn = xTaskCreate((TaskFunction_t )MotorCtrl_Task, /* 任务入口函数 */
	(const char* )"MotorCtrl_Task",/* 任务名字 */
	(uint16_t )512, /* 任务栈大小 */
	(void* )NULL, /* 任务入口函数参数 */
	(UBaseType_t )5, /* 任务的优先级 */
	(TaskHandle_t* )&MotorCtrl_Task_Handle);/* 任务控制块指针 */
	if (pdPASS == xReturn)
		printf("创建 MotorCtrl_Task 任务成功!\r\n");
	
	
	
	
	taskEXIT_CRITICAL(); //退出临界区
	osThreadTerminate(FreeRTOSTaskCreHandle);//

}




void UartConfig()
{
	__HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);
	HAL_UART_Receive_DMA(&huart3, uartDMA_data.rxBuf, BUFFER_SIZE);
}

/******************************************************************************************
*** 函数名称: Debug_Printf
*** 输入参数: 无
*** 返 回 值: 无
*** 说    明：自定义串口 printf功能
*** 功能说明：
1、sizeof返回定义arr数组时，编译器为其分配的数组空间大小，不关心里面存了多少数据。
2、strlen只关心存储的数据内容，不关心空间的大小和类型。
3、串口DMA方式打印的数组需要保留，DMA直接操作的是内存，如果DMA未打印完成就清空数组会出现数据打印不完整的情况
***	编者										时间										版本
***	WL											2020/12/8								V0.1
******************************************************************************************/
void Debug_Printf(char *format, ...)
{
	va_list ap;
	va_start(ap, format);																			//初始化 ap 变量
	vsnprintf((char *)uartDMA_data.txBuf, sizeof(uartDMA_data.txBuf), format, ap);		//可变参数。用于向字符串中打印数据、数据格式用户自定义
	va_end(ap);																								//允许使用了 va_start 宏的带有可变参数的函数返回
	HAL_UART_Transmit_DMA(UART_DEBUG, (uint8_t *)uartDMA_data.txBuf, strlen((char *)uartDMA_data.txBuf));	//打印数据
	
}



static void UartTx_Task(void* pvParameters)
{
	
	char txBuff[30]={'I','M','U',':'};
	char *end="\r\n";
	taskENTER_CRITICAL(); //进入临界区
	UartConfig();
	taskEXIT_CRITICAL(); //退出临界区
  for(;;)
  {
		vTaskDelay(5);		
		memcpy(txBuff+4,&Roll,4);
		memcpy(txBuff+8,&Pitch,4);
		memcpy(txBuff+12,&EncoderValue.LValue,4);
		memcpy(txBuff+16,&EncoderValue.RValue,4);
		memcpy(txBuff+20,end,2); 		
		HAL_UART_Transmit_DMA(UART_DEBUG, (uint8_t *)txBuff,22);	//打印数据
		//printf(txBuff);
  }
}


static void UartRx_Task(void* pvParameters)
{
	taskENTER_CRITICAL(); //进入临界区
	UartConfig();
	taskEXIT_CRITICAL(); //退出临界区
	while(1)
	{
		ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
		HAL_UART_Receive_DMA(&huart3, uartDMA_data.rxBuf, BUFFER_SIZE);//重新打开DMA接受
		if(memcmp(uartDMA_data.rxBuf, "Duty:", 5)==0)//包头确认
		{
			memcpy(&LMotor.duty,uartDMA_data.rxBuf+5,4);
			memcpy(&RMotor.duty,uartDMA_data.rxBuf+9,4);
		}	
	}
}

void Uart3ReceiveCallback(void)
{
	if((__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET))  //获取IDLE标志位，idle标志被置位
	{
		__HAL_UART_CLEAR_IDLEFLAG(&huart3);														//清除空闲中断标志位
		HAL_UART_DMAStop(&huart3);																	//停止串口DMA功能	
		uartDMA_data.recive_count = BUFFER_SIZE - huart3.hdmarx->Instance->CNDTR;					//接收数据计数	
		vTaskNotifyGiveFromISR(UartRx_Task_Handle,NULL);
	}
}



static void LED_Task(void* parameter)
{
	static int Count=0;
	while (1) 
	{
		vTaskDelay(500); /* 延时 500 个 tick */
		Count++;
		//printf("Count:%d\r\n",Count);
	}
}

